package cc.magicjson.util;

import org.springframework.beans.BeanUtils;

import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;

/**
 * {@link BeanUtils#copyProperties(Object, Object)}
 *
 * @author <a href="mailto:it_magicjson@163.com">MagicJson</a>
 * @since 1.0.0
 */
public class PropertyCopierUtils {


    /**
     * 将源对象的属性复制到目标对象
     *
     * @param source 源对象
     * @param target 目标对象
     * @param <S>    源对象类型
     * @param <R>    目标对象类型
     * @return 目标对象
     */
    public static <S, R> R copyProperties(S source, R target) {
        return getOptionalCopiedBean(source, target).orElse(null);
    }

    /**
     * 复制源对象的所有属性到目标对象，并返回一个表示复制结果的 Optional 对象。
     *
     * @param source 源对象
     * @param target 目标对象
     * @return 包含复制结果的 Optional 对象
     */
    public static <S, R> Optional<R> getOptionalCopiedBean(S source, R target) {
        if (source == null || target == null) {
            return Optional.empty();
        }

        try {
            // 复制所有属性
            BeanUtils.copyProperties(source, target);
            return Optional.of(target); // 复制成功，返回目标对象
        } catch (Exception e) {
            // 复制过程中出现异常
            return Optional.empty();
        }
    }


    /**
     * 将源对象的属性复制到指定类型的目标对象，并返回该目标对象。
     *
     * @param <S>   源对象的类型
     * @param <R>>  目标对象的类型
     * @param clazz 目标对象的类类型
     * @return 填充后的目标对象
     */
    public static <S, R> Function<S, R> copyToTarget(Class<R> clazz) {
        return source -> {
            if (isNull(source)) {
                return null;
            }
            R target;
            try {
                Constructor<R> declaredConstructor = clazz.getDeclaredConstructor();
                declaredConstructor.setAccessible(true);
                target = declaredConstructor.newInstance();
                BeanUtils.copyProperties(source, target);
            } catch (Exception e) {
                throw new RuntimeException("Failed to instantiate object of type: " + clazz.getName(), e);
            }
            return target;
        };
    }


    /**
     * 使用提供的转换函数将原集合中的每个元素转换为目标集合中的元素，并返回新集合。
     *
     * @param <S>         源对象的类型
     * @param <R>         目标对象的类型
     * @param source      原始集合
     * @param transformer 转换函数
     * @return 新的集合
     */
    public static <S, R> List<R> transform(Collection<S> source, Function<S, R> transformer) {
        if (isNull(source) || isNull(transformer)) {
            throw new IllegalArgumentException("Source collection and transformer must not be null");
        }
        return source.stream()
            .map(transformer)
            .collect(Collectors.toList());
    }


}
